<?php
package("Utils");
package("Core");

define("JUNCTION_ADAPTER_GET", "get");
define("JUNCTION_ADAPTER_SET", "set");

/**
 * Move between a junction class and a plain old PHP class
 *
 * <p>The purpose of this class is to act as a bridge between the client objects and
 * the junction mapper class.  The client and the mapper class should not have knowledge
 * of eachother, and insofar as possible this class should know as little as it can about
 * those classes.
 * <p>Of course in order to do its job this class must have some knowledge about the
 * client, and the mapper class.  Spefically, this class expects the client to implement
 * get and set methods for each property in the schema file.  The methods should be of
 * the form:<br />
 * <code>getEmail()</code>
 * <p>Likewise, this class expects the mapper class to be iterable, and will iterate
 * over the properties contained in said class.  In this manner it will pass state
 * to and from the client.
 *
 * @see Core_Class
 */
class Core_Adapter {
	
	/**
	 * Junction class definition
	 *
	 * @var Core_Class
	 */
	private $_class;

	public function __construct(Core_Class $class) {
		$this->_class = $class;
	}
	
	/**
	 * Retrieve an object's state from the database
	 * 
	 * <p>The object will be selected based on its id.  Its state will
	 * be updated with the contents in the table row.
	 *
	 * @param unknown_type $object
	 */
	public function restore(& $object) {
		$this->push($object);
		$this->_class->restore();
		$this->pull($object);
	}
	
	/**
	 * Save the object's state to the database
	 * 
	 * <p>Once saved set any fields necessary so that the object's state
	 * reflects the newly altered table row.
	 *
	 * @param unknown_type $object
	 */
	public function save(& $object) {
		$this->push($object);
		$this->_class->save();
		$this->pull($object);
	}
	
	public function remove(& $object) {
		$this->push($object);
		$this->_class->remove();
		$this->pull($object);
	}
	
	/**
	 * Push all the object's data into the class' properties
	 *
	 * @param unknown_type $object
	 */
	private function push(& $object) {
		foreach ($this->_class as $property) {
			$this->getProperty($object, $property);
		}
	}
	
	/**
	 * Pull all of the class' properties' data into the object
	 */
	private function pull(& $object) {
		foreach ($this->_class as $property) {
			$this->setProperty($object, $property);
		}
	}
	
	/**
	 * Call the getter for the given property on the object
	 * 
	 * @throws Core_Exception
	 *
	 * @param unknown_type $object
	 * @param Core_Property $property
	 */
	private function getProperty(& $object, Core_Property & $property) {
		try {
			$property->value = Utils_Reflection_Facade::invokeArgs($object, 
							JUNCTION_ADAPTER_GET . ucfirst($property->name), 
							array());
		} catch (Utils_Reflection_Exception $e) {
			throw new Core_Exception($e);
		}
	}
	
	/**
	 * Call the setter for the given property on the object
	 * 
	 * @throws Core_Exception
	 *
	 * @param unknown_type $object
	 * @param Core_Property $property
	 */
	private function setProperty(& $object, Core_Property & $property) {
		try {
			Utils_Reflection_Facade::invokeArgs($object, 
							JUNCTION_ADAPTER_SET . ucfirst($property->name), 
							array($property->value));
		} catch (Utils_Reflection_Exception $e) {
			throw new Core_Exception($e);
		}
	}
}
?>